Skip to content

docs(model): document bedrockGeoRegion and the global-vs-geo tradeoff - #799

Closed
isadeks wants to merge 2 commits into
mainfrom
docs/740-bedrock-geo-region
Closed

docs(model): document bedrockGeoRegion and the global-vs-geo tradeoff#799
isadeks wants to merge 2 commits into
mainfrom
docs/740-bedrock-geo-region

Conversation

@isadeks

@isadeks isadeks commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Part of #740. Closes the documentation gap I raised reviewing #764.

Why

bedrockGeoRegion (added in #764) was documented nowhere — not in docs/guides/DEVELOPER_GUIDE.md, not in Model-configuration.md, not in cdk.json. The synth-time error message names the key, but only helps someone who already knows it exists.

That matters more than usual because #740 is the documentation tracking issue, and #742 created the canonical model-configuration reference specifically so model settings stop being scattered. A new key that decides which geography every inference profile routes through belongs in it.

What

A section covering:

  • what the key does, and how to set it (-c bedrockGeoRegion=global or cdk.json context);
  • accepted values, framed as what the CDK models rather than a copied list — global, us, us-gov, eu, apac, jp, au;
  • that an unrecognized value fails at synth, and why that is the right behaviour: an invented geography yields a well-formed ARN for a profile that does not exist, so the grant would authorize nothing and the agent would fail at turn 0 with AccessDenied and nothing to explain why;
  • that one value drives both grant sites and ANTHROPIC_DEFAULT_HAIKU_MODEL, so a deployment cannot grant one geography while calling another.

The tradeoff, stated as a choice rather than a default: global. routes to any supported commercial Region, giving better throughput and resilience under burst — worth having for tasks that run hours. A geo profile keeps inference in that geography, which is what a data-residency requirement demands. This is the material half for #747, which flips the default to global.

Plus the two failure modes that surface at runtime rather than synth: a model with no profile in the target geography, and account-level Bedrock access not covering that geography's entitlements.

Two corrections

#764 made two existing statements stale:

statement was now
bare-vs-prefixed rule grant sites add us. add the configured geo
layer-1 table row bedrockModels only + bedrockGeoRegion

One question the guide implied but never answered

Changing the geography needs a redeploy, because the IAM grants are scoped to explicit profile ARNs resolved at synth. Switching among already-granted models does not — that is a DynamoDB write via layer 4. The layering table implied this; it now says so.

Verification

Starlight mirror regenerated with mise //docs:sync — both files carry the new content, and mise //docs:build is green (78 pages). Docs-only; no source changes.

The `bedrockGeoRegion` context key added in #764 was documented nowhere — not in
the developer guide, not in the canonical model-configuration reference #742
created for exactly this, not in cdk.json. The synth-time error names the key, but
only for someone who already knows it exists.

Adds a section covering what the key does, its accepted values (derived from what
the CDK models: global, us, us-gov, eu, apac, jp, au), and that an unrecognized
value fails at synth rather than producing a well-formed ARN for a profile that
does not exist.

Also states the choice, since it is a real tradeoff rather than a default to
accept: `global.` routes to any supported commercial Region for better throughput
and resilience under burst, while a geo profile is what a data-residency
requirement demands. Plus the two things that fail at runtime rather than synth —
a model without a profile in the target geography, and account-level Bedrock
access not covering that geography's entitlements.

Two existing statements went stale with #764 and are corrected here: the
bare-vs-prefixed rule described the grant sites as adding `us.` specifically, and
the layer-1 table row described only `bedrockModels`. Both now read in terms of the
configured geography.

Answers a question that the layering table implies but never states: changing the
geography needs a redeploy, because the grants are scoped to profile ARNs resolved
at synth, whereas switching among already-granted models does not.

Starlight mirror regenerated with `mise //docs:sync`; docs build green.
@isadeks
isadeks requested review from a team as code owners August 26, 2026 16:22
isadeks added a commit that referenced this pull request Aug 27, 2026
Addresses all six review findings on the geo switch. The first was a real defect,
not a documentation error.

FINDING 1 — the one-line rollback was false. `synth -c bedrockGeoRegion=us` granted
`us.` profiles while the agent still asked for `global.anthropic.claude-opus-5`,
because the stack injected only the AUXILIARY model into the runtime env and never
the main one. The main model came from a Python literal that a geography change does
not touch, so every task with no per-repo override would fail at turn 0 with
AccessDenied. My own PR body half-knew this — the prose said "roll back context and
defaults together" while the summary claimed one line.

Fixed by removing the divergence rather than re-syncing literals: both models are
now injected from the resolved geography, via one shared helper, on BOTH substrates
(the ECS task definitions set neither var either, so an ECS task had the same
mismatch). Verified by synthesizing both geographies: grants, AgentCore env and ECS
env now agree in each, so the rollback genuinely is one context value.

Also fixes the fifth stale default the review found, TaskConfig.haiku_model, which I
had missed entirely while counting four.

FINDING 2 — the generalized allow-list invariant was too weak in both directions. It
only proved entries were paired WITHIN the list, which is satisfiable while wrong:
three granted models had no `global.` form (a workflow pinning one was rejected at
admission), and the reviewer's invented pair passed all 22 tests despite being
granted nothing. Replaced with parity against DEFAULT_BEDROCK_MODEL_IDS across the
deployable geographies, in both directions, and confirmed the reviewer's exact
mutation now fails.

FINDING 3 — the `--model` guard let through a well-formed but ungranted model. My
justification for that was wrong: I claimed the CLI cannot read `bedrockModels`, but
`get-template` recovers the granted set from the profile ARNs using credentials the
CLI already needs. Added a `BedrockModelIds` output — a documented contract rather
than a regex over CloudFormation — and the guard now rejects an ungranted model,
listing what the stack does grant. Also fixes the reverse-compatibility bug: with no
geography exported, the bare-id error no longer prescribes `us.`, which a
default-global stack does not grant.

FINDING 4 — doctor's profile check is relabelled "visible" and its detail states that
resolution happens under operator credentials and does not prove the workload role
can invoke. The narrow wording was already accurate, but a PASS feeding "All checks
passed" still read as readiness.

FINDINGS 5-6 — carries #799's documentation so this branch is not self-contradictory,
corrects the onboarding and troubleshooting skills that recommended `us.` overrides
this branch would now reject (and still called Sonnet 4.6 the default), and fixes the
stale "default us" wording in the new output description.

One test rewritten rather than re-pinned: the agent's haiku-default test asserted
`startswith("us.")` when its stated intent was "must be a profile, not a bare id". It
now asserts a geo prefix, so it tests the property instead of a geography that is a
deploy-time choice.
@isadeks

isadeks commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #806, which carries this content plus the geo flip and the review fixes. Verified before closing: every distinctive section here (Choosing the inference-profile geography, the residency caveat, the fail-at-synth rationale, the redeploy note) is present on #806's branch, with strictly newer model strings — this branch still says us.anthropic.claude-opus-5 where #806 says global..

Closing rather than rebasing, since a rebase would produce an empty diff and #806 needs no doc changes on top.

@isadeks isadeks closed this Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant